package com.gaokao.demo.filter;

import cn.hutool.json.JSONUtil;
import com.gaokao.demo.constants.Constant;
import com.gaokao.demo.utils.JwtTokenUtil;
import com.gaokao.demo.vo.ResultResponse;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录验证
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

  private AuthenticationManager authenticationManager;

  public JWTAuthenticationFilter(AuthenticationManager authenticationManager)
  {
    this.authenticationManager = authenticationManager;
  }

  /**
   * 验证操作 接收并解析用户凭证
   */
  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    // 从输入流中获取到登录的信息
    // 创建一个token并调用authenticationManager.authenticate() 让Spring security进行验证
    return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getParameter("username"),request.getParameter("password")));
  }

  /**
   * 验证【成功】后调用的方法
   * 若验证成功 生成token并返回
   */
  @Override
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException {
    User user= (User) authResult.getPrincipal();

    // 从User中获取权限信息
    Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
    // 创建Token
    String token = JwtTokenUtil.createToken(user.getUsername(), authorities.toString());

    // 设置编码 防止乱码问题
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json; charset=utf-8");
    // 在请求头里返回创建成功的token
    // 设置请求头为带有"Bearer "前缀的token字符串
    response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token);

    // 处理编码方式 防止中文乱码
    response.setContentType("text/json;charset=utf-8");
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("token",JwtTokenUtil.TOKEN_PREFIX + token);
    ResultResponse resultResponse = new ResultResponse();
    resultResponse.setCode(20000);
    resultResponse.setMessage("登录成功");
    resultResponse.setData(map);
    // 将反馈塞到HttpServletResponse中返回给前台
    response.getWriter().write(JSONUtil.toJsonStr(resultResponse));
  }

  /**
   * 验证【失败】调用的方法
   */
  @Override
  protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {

    ResultResponse resultResponse = new ResultResponse();
    System.out.println(failed.getCause());
    // 账号过期
    if (failed.getCause() instanceof AccountExpiredException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("账号过期");
    }
    // 密码错误
    else if (failed.getCause() instanceof BadCredentialsException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("密码错误");
    }
    // 密码过期
    else if (failed.getCause() instanceof CredentialsExpiredException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("密码过期");
    }
    // 账号不可用
    else if (failed.getCause() instanceof DisabledException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("用户未激活");
    }
    //账号锁定
    else if (failed.getCause() instanceof LockedException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("账号锁定");
    }
    // 用户不存在
    else if (failed instanceof InternalAuthenticationServiceException) {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("用户不存在");
    }
    // 其他错误
    else {
      resultResponse.setCode(Constant.FAIL_CODE);
      resultResponse.setMessage("未知异常");
    }

    // 处理编码方式 防止中文乱码
    response.setContentType("text/json;charset=utf-8");
    // 将反馈塞到HttpServletResponse中返回给前台
    response.getWriter().write(JSONUtil.toJsonStr(resultResponse));
  }
}
